import cv2
import socket
import struct
import numpy as np
import threading
import time
from config.settings import CAMERA_CONFIG

class VideoStreamServer:
    """
    视频流服务器 - 用于实时传输摄像头画面
    """
    
    def __init__(self, host='0.0.0.0', port=9999):
        self.host = host
        self.port = port
        self.server_socket = None
        self.is_running = False
        self.clients = []
        self.frame_buffer = None
        self.camera = None
        
    def start_server(self):
        """启动视频流服务器"""
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.server_socket.bind((self.host, self.port))
            self.is_running = True
            
            # 启动摄像头
            self.camera = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
            self.camera.set(3, CAMERA_CONFIG['width'])
            self.camera.set(4, CAMERA_CONFIG['height'])
            
            print(f"视频流服务器启动在 {self.host}:{self.port}")
            
            # 启动视频捕获线程
            capture_thread = threading.Thread(target=self._capture_frames)
            capture_thread.daemon = True
            capture_thread.start()
            
            # 启动客户端处理线程
            client_thread = threading.Thread(target=self._handle_clients)
            client_thread.daemon = True
            client_thread.start()
            
            return True
            
        except Exception as e:
            print(f"服务器启动失败: {e}")
            return False
    
    def stop_server(self):
        """停止视频流服务器"""
        self.is_running = False
        if self.camera:
            self.camera.release()
        if self.server_socket:
            self.server_socket.close()
        print("视频流服务器已停止")
    
    def _capture_frames(self):
        """捕获视频帧"""
        while self.is_running:
            ret, frame = self.camera.read()
            if ret:
                # 压缩帧
                encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 80]
                result, encoded_frame = cv2.imencode('.jpg', frame, encode_param)
                
                if result:
                    self.frame_buffer = encoded_frame.tobytes()
            
            time.sleep(1 / CAMERA_CONFIG['fps'])
    
    def _handle_clients(self):
        """处理客户端连接和数据发送"""
        while self.is_running:
            if self.frame_buffer:
                try:
                    # 接收客户端消息
                    data, address = self.server_socket.recvfrom(1024)
                    
                    if data == b'REQUEST_FRAME':
                        # 发送帧长度
                        length = struct.pack('i', len(self.frame_buffer))
                        self.server_socket.sendto(length, address)
                        
                        # 发送帧数据
                        self.server_socket.sendto(self.frame_buffer, address)
                    
                    elif data == b'REGISTER_CLIENT':
                        if address not in self.clients:
                            self.clients.append(address)
                            print(f"新客户端注册: {address}")
                    
                    elif data == b'UNREGISTER_CLIENT':
                        if address in self.clients:
                            self.clients.remove(address)
                            print(f"客户端注销: {address}")
                    
                    elif len(data) == 1 and data[0] == 1:  # 关闭信号
                        print(f"收到关闭信号 from {address}")
                        if address in self.clients:
                            self.clients.remove(address)
                
                except socket.error as e:
                    print(f"Socket错误: {e}")
            
            time.sleep(0.01)


class VideoStreamClient:
    """
    视频流客户端 - 用于接收和显示视频流
    """
    
    def __init__(self, server_host='localhost', server_port=9999):
        self.server_host = server_host
        self.server_port = server_port
        self.client_socket = None
        self.is_connected = False
        self.current_frame = None
        
    def connect(self):
        """连接到视频流服务器"""
        try:
            self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.client_socket.settimeout(2.0)
            
            # 注册客户端
            self.client_socket.sendto(b'REGISTER_CLIENT', (self.server_host, self.server_port))
            self.is_connected = True
            print(f"已连接到视频流服务器 {self.server_host}:{self.server_port}")
            return True
            
        except Exception as e:
            print(f"连接失败: {e}")
            return False
    
    def disconnect(self):
        """断开连接"""
        if self.client_socket:
            try:
                self.client_socket.sendto(b'UNREGISTER_CLIENT', (self.server_host, self.server_port))
            except:
                pass
            self.client_socket.close()
        self.is_connected = False
        print("已断开视频流连接")
    
    def get_frame(self):
        """获取一帧视频"""
        if not self.is_connected:
            return None
        
        try:
            # 请求帧
            self.client_socket.sendto(b'REQUEST_FRAME', (self.server_host, self.server_port))
            
            # 接收帧长度
            length_data, _ = self.client_socket.recvfrom(4)
            length = struct.unpack('i', length_data)[0]
            
            # 接收帧数据
            frame_data, _ = self.client_socket.recvfrom(length)
            
            # 解码帧
            frame_array = np.frombuffer(frame_data, dtype=np.uint8)
            frame = cv2.imdecode(frame_array, cv2.IMREAD_COLOR)
            
            self.current_frame = frame
            return frame
            
        except socket.timeout:
            print("接收帧超时")
            return None
        except Exception as e:
            print(f"获取帧失败: {e}")
            return None
    
    def start_stream_display(self, window_name='Video Stream'):
        """
        开始显示视频流
        """
        if not self.connect():
            return
        
        print("开始显示视频流，按ESC退出")
        
        while self.is_connected:
            frame = self.get_frame()
            if frame is not None:
                cv2.imshow(window_name, frame)
            
            # 退出条件
            if cv2.waitKey(1) & 0xFF == 27:  # ESC键
                break
        
        self.disconnect()
        cv2.destroyAllWindows()


class CameraManager:
    """
    摄像头管理器 - 统一管理摄像头操作
    """
    
    def __init__(self):
        self.camera = None
        self.is_camera_open = False
        
    def open_camera(self, camera_index=0):
        """打开摄像头"""
        try:
            self.camera = cv2.VideoCapture(camera_index + cv2.CAP_DSHOW)
            self.camera.set(3, CAMERA_CONFIG['width'])
            self.camera.set(4, CAMERA_CONFIG['height'])
            
            if self.camera.isOpened():
                self.is_camera_open = True
                print("摄像头打开成功")
                return True
            else:
                print("摄像头打开失败")
                return False
                
        except Exception as e:
            print(f"摄像头打开异常: {e}")
            return False
    
    def close_camera(self):
        """关闭摄像头"""
        if self.camera:
            self.camera.release()
            self.is_camera_open = False
            print("摄像头已关闭")
    
    def get_frame(self):
        """获取当前帧"""
        if not self.is_camera_open:
            return None, False
        
        ret, frame = self.camera.read()
        return frame, ret
    
    def capture_photo(self, save_path):
        """拍摄照片并保存"""
        if not self.is_camera_open:
            return False
        
        frame, ret = self.get_frame()
        if ret:
            cv2.imwrite(save_path, frame)
            print(f"照片已保存: {save_path}")
            return True
        return False
    
    def record_video(self, save_path, duration=10, fps=30):
        """
        录制视频
        duration: 录制时长(秒)
        fps: 帧率
        """
        if not self.is_camera_open:
            return False
        
        # 定义视频编码器
        fourcc = cv2.VideoWriter_fourcc(*'XVID')
        out = cv2.VideoWriter(save_path, fourcc, fps, 
                             (CAMERA_CONFIG['width'], CAMERA_CONFIG['height']))
        
        print(f"开始录制视频，时长: {duration}秒")
        start_time = time.time()
        
        while self.is_camera_open:
            frame, ret = self.get_frame()
            if ret:
                out.write(frame)
                cv2.imshow('Recording...', frame)
            
            # 检查录制时长
            if time.time() - start_time >= duration:
                break
            
            # 退出条件
            if cv2.waitKey(1) & 0xFF == 27:  # ESC键
                break
        
        out.release()
        cv2.destroyAllWindows()
        print(f"视频录制完成: {save_path}")
        return True
    
    def detect_faces(self, frame):
        """在帧中检测人脸"""
        face_cascade = cv2.CascadeClassifier(
            './haarcascades/haarcascade_frontalface_default.xml'
        )
        
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = face_cascade.detectMultiScale(
            gray,
            scaleFactor=CAMERA_CONFIG['face_detection_scale'],
            minNeighbors=CAMERA_CONFIG['face_detection_neighbors']
        )
        
        return faces
    
    def draw_faces(self, frame, faces, color=(255, 0, 0), thickness=2):
        """在帧上绘制人脸框"""
        for (x, y, w, h) in faces:
            cv2.rectangle(frame, (x, y), (x + w, y + h), color, thickness)
        return frame
    
    def get_camera_info(self):
        """获取摄像头信息"""
        if not self.is_camera_open:
            return None
        
        info = {
            'width': int(self.camera.get(cv2.CAP_PROP_FRAME_WIDTH)),
            'height': int(self.camera.get(cv2.CAP_PROP_FRAME_HEIGHT)),
            'fps': self.camera.get(cv2.CAP_PROP_FPS),
            'brightness': self.camera.get(cv2.CAP_PROP_BRIGHTNESS),
            'contrast': self.camera.get(cv2.CAP_PROP_CONTRAST),
            'saturation': self.camera.get(cv2.CAP_PROP_SATURATION)
        }
        
        return info


class AttendanceCamera:
    """
    考勤专用摄像头类
    """
    
    def __init__(self):
        self.camera_manager = CameraManager()
        self.face_recognizer = FaceRecognizer()
        self.current_class = None
        
    def initialize_attendance(self, class_number):
        """初始化考勤"""
        self.current_class = class_number
        try:
            self.face_recognizer.load_class_model(class_number)
            return True
        except FileNotFoundError:
            print(f"班级 {class_number} 的识别模型未找到")
            return False
    
    def start_attendance_check(self, on_recognized_callback=None):
        """开始考勤检查"""
        if not self.current_class:
            print("请先初始化考勤")
            return
        
        if not self.camera_manager.open_camera():
            print("摄像头打开失败")
            return
        
        print("开始考勤检查，按ESC退出")
        recognized_users = set()  # 记录已识别的用户，避免重复
        
        while self.camera_manager.is_camera_open:
            frame, ret = self.camera_manager.get_frame()
            if not ret:
                continue
            
            # 识别人脸
            recognition_results = self.face_recognizer.recognize_face(frame)
            
            # 处理识别结果
            for result in recognition_results:
                x, y, w, h = result['bbox']
                
                if result['recognized']:
                    user_id = result['user_id']
                    confidence = result['confidence']
                    
                    # 绘制绿色框 - 识别成功
                    color = (0, 255, 0)
                    label = f"ID: {user_id} ({confidence:.1f}%)"
                    
                    # 如果是新识别的用户，触发回调
                    if user_id not in recognized_users:
                        recognized_users.add(user_id)
                        if on_recognized_callback:
                            on_recognized_callback(user_id, confidence)
                            print(f"识别到用户: {user_id}, 置信度: {confidence:.1f}%")
                
                else:
                    # 绘制红色框 - 未识别
                    color = (0, 0, 255)
                    label = f"Unknown ({result['confidence']:.1f}%)"
                
                # 绘制边界框和标签
                cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
                cv2.putText(frame, label, (x, y - 10), 
                           cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
            
            # 显示统计信息
            cv2.putText(frame, f"已识别: {len(recognized_users)}人", 
                       (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
            
            cv2.imshow('Attendance Check', frame)
            
            # 退出条件
            if cv2.waitKey(1) & 0xFF == 27:  # ESC键
                break
        
        self.camera_manager.close_camera()
        cv2.destroyAllWindows()
        return list(recognized_users)


# 全局摄像头管理实例
camera_manager = CameraManager()
attendance_camera = AttendanceCamera()

# 视频流服务器实例
video_server = VideoStreamServer()
video_client = VideoStreamClient()